Я пытаюсь объединить несколько документов Word (.docx), используя OpenXML в C#. Само слияние работает, но у меня есть постоянная проблема с пронумерованными и пуленами списками. Второе
имеет цифры → все списки в объединенном файле становятся числами. < /li>
Если в первом документе есть цифры, а второй имеет пули → Все списки в объединенном файле становятся пулями. /> < /ul>
Кажется, что в целевом документе < /strong> «strong>» в последнее время. Документ. < /li>
Создание новых атрибутов NSID и имен в списке, чтобы избежать столкновений. < /li>
Образцы отслеживания с словарями для Numid и Abstractnumid. < /li>
Обеспечение начального оборудования. Магия происходит в numberHelper.mycodeHelper () . Я хотел бы избежать публикации всего этого кода и просто дать мой вывод XML для каждого источника и нумерацию. Xml целевого документа, и, возможно, кто -то сможет сказать мне, где я ошибаюсь, потому что, как я понимаю, XML не имеет никаких явных идентификационных выпусков. var targetDoc = targetWml
NumberHelper.ResetGlobalMaps();
foreach (var sourceDoc in sourceDocs)
{
var result = NumberHelper.MyCodeHelper(WordprocessingDocument sourceDoc, WmlDocument targetDoc);
targetDoc = result.UpdatedDoc;
updatedParagraphs = result.UpdatedParagraphs;
//I then have some code here that I am using to insert the result.UpdatedPargraphs into the targetDoc. This code is not having any issues. It is a numbering.xml issue, I am almost certain.
}
source1 xml, который я вставляю и изображает его появление в документе.
This is atest
asdfads
fasdfasdfad
fasdfads
asdfasdf
asdfasdfsdf
asdfdsaf
adsfasdfasdf
asdfasdfasdf
asdfadsfasdfdsafasdf
source2 xml, который я вставляю и изображает его появление в документе.
This iadfasdf adf
asdfasd
fasdfasdf
asdfasdfasd
fasdfasd
fadsafs
adsfasdfasd
asdfa
sdfasdfadsf
asdfsdf
< /code>
Результаты - как он появляется в окончательном документе. РЕДАКТИРОВАТЬ: Удал окончательный документ XML для публикации кода ниже:
edit:
ЗДЕСЬ. Я должен удалить вывод XML, который я получаю, чтобы опубликовать это. < /P>
public static class NumberingHelper
{
// Maps (docId, srcAbsId, signature) → mapped abstractNumId
private static readonly Dictionary GlobalAbstractNumIdMap
= new Dictionary();
// Maps (docId, srcNumId, signature) → mapped numId
private static readonly Dictionary GlobalNumIdMap
= new Dictionary();
// Maps srcNumId → absSignature (per document, temporary)
private static readonly Dictionary SrcNumToAbsSignature
= new Dictionary();
private static int maxAbsNumId = 0;
private static int maxNumId = 0;
public static void ResetGlobalMaps()
{
GlobalAbstractNumIdMap.Clear();
GlobalNumIdMap.Clear();
SrcNumToAbsSignature.Clear();
}
public static NumberingResult CopyNumberingAndParagraphs(
WordprocessingDocument sourceDoc,
WmlDocument targetWml)
{
XNamespace w = "http://schemas.openxmlformats.org/wordp ... /2006/main";
//XNamespace w = "";
byte[] targetBytes = targetWml.DocumentByteArray;
// 1) Load source numbering
XDocument sourceNumbering = null;
if (sourceDoc?.MainDocumentPart?.NumberingDefinitionsPart != null)
{
using (var reader = new StreamReader(sourceDoc.MainDocumentPart.NumberingDefinitionsPart.GetStream()))
{
sourceNumbering = XDocument.Load(reader);
}
}
if (sourceNumbering == null)
return new NumberingResult { UpdatedDoc = targetWml, UpdatedParagraphs = new List() };
// 2) Load target numbering (or create new)
XDocument targetNumbering;
using (var msLoad = new MemoryStream(targetBytes))
using (var wDocLoad = WordprocessingDocument.Open(msLoad, false))
{
var mainPart = wDocLoad.MainDocumentPart;
var numberingPart = mainPart.NumberingDefinitionsPart;
if (numberingPart != null)
{
using (var reader = new StreamReader(numberingPart.GetStream()))
targetNumbering = XDocument.Load(reader);
}
else
{
targetNumbering = new XDocument(
new XElement(w + "numbering",
new XAttribute(XNamespace.Xmlns + "w", w.NamespaceName)));
}
}
// 3) Determine max IDs in target numbering
int maxAbsNumId = targetNumbering.Descendants(w + "abstractNum")
.Select(a => (int?)a.Attribute(w + "abstractNumId"))
.DefaultIfEmpty(0)
.Max() ?? 0;
int maxNumId = targetNumbering.Descendants(w + "num")
.Select(n => (int?)n.Attribute(w + "numId"))
.DefaultIfEmpty(0)
.Max() ?? 0;
// Unique prefix for this source doc instance
string docGuid = (sourceDoc?.PackageProperties?.Identifier) ?? Guid.NewGuid().ToString("N");
var srcNumToAbsSignature = new Dictionary();
// 4) Copy elements from source
foreach (var srcNum in sourceNumbering.Descendants(w + "num"))
{
var numAttr = srcNum.Attribute(w + "numId");
if (numAttr == null || !int.TryParse(numAttr.Value, out int srcNumId))
continue;
var absElem = srcNum.Element(w + "abstractNumId");
if (absElem == null)
continue;
var absAttr = absElem.Attribute(w + "val");
if (absAttr == null || !int.TryParse(absAttr.Value, out int srcAbsId))
continue;
var srcAbs = sourceNumbering.Descendants(w + "abstractNum")
.FirstOrDefault(a =>
{
var aAttr = a.Attribute(w + "abstractNumId");
return aAttr != null &&
int.TryParse(aAttr.Value, out int v) &&
v == srcAbsId;
});
if (srcAbs == null)
continue;
// Build unique signature
string absSignature = string.Join("|",
new[] {
(string)srcAbs.Element(w + "multiLevelType")?.Attribute(w + "val") ?? "",
(string)srcAbs.Element(w + "nsid")?.Attribute(w + "val") ?? ""
}
.Concat(
srcAbs.Elements(w + "lvl").Select(l =>
$"{(int?)l.Attribute(w + "ilvl") ?? -1}-" +
$"{(string)l.Element(w + "numFmt")?.Attribute(w + "val") ?? ""}-" +
$"{(string)l.Element(w + "lvlText")?.Attribute(w + "val") ?? ""}-" +
$"{(string)l.Element(w + "lvlJc")?.Attribute(w + "val") ?? ""}-" +
$"{(string)l.Element(w + "isLgl")?.Attribute(w + "val") ?? ""}"
)
)
);
var absKey = ((docGuid, srcAbsId), absSignature + "|" + docGuid);
if (!GlobalAbstractNumIdMap.TryGetValue(absKey, out int mappedAbsId))
{
var clonedAbs = new XElement(srcAbs);
mappedAbsId = ++maxAbsNumId;
clonedAbs.SetAttributeValue(w + "abstractNumId", mappedAbsId);
// generate fresh nsid
var newNsid = Guid.NewGuid().ToString("N").Substring(0, 8).ToUpperInvariant();
var nsidElem = clonedAbs.Element(w + "nsid");
if (nsidElem != null) nsidElem.SetAttributeValue(w + "val", newNsid);
else clonedAbs.Add(new XElement(w + "nsid", new XAttribute(w + "val", newNsid)));
// give it its own name
var nameElem = clonedAbs.Element(w + "name");
if (nameElem != null) nameElem.SetAttributeValue(w + "val", $"List_{newNsid}");
else clonedAbs.Add(new XElement(w + "name", new XAttribute(w + "val", $"List_{newNsid}")));
// ensure multiLevelType is preserved
var multiElem = srcAbs.Element(w + "multiLevelType");
if (multiElem != null)
clonedAbs.Add(new XElement(w + "multiLevelType",
new XAttribute(w + "val", multiElem.Attribute(w + "val")?.Value)));
targetNumbering.Root.Add(clonedAbs);
GlobalAbstractNumIdMap[absKey] = mappedAbsId;
}
int newNumForThis = ++maxNumId;
GlobalNumIdMap[(docGuid, srcNumId, absSignature)] = newNumForThis;
srcNumToAbsSignature[srcNumId] = absSignature;
var clonedNum = new XElement(srcNum);
clonedNum.SetAttributeValue(w + "numId", newNumForThis);
var absRefElem = clonedNum.Element(w + "abstractNumId");
if (absRefElem != null)
absRefElem.SetAttributeValue(w + "val", mappedAbsId);
else
clonedNum.Add(new XElement(w + "abstractNumId",
new XAttribute(w + "val", mappedAbsId)));
// Add lvlOverride resets
var mappedAbsElem = targetNumbering
.Descendants(w + "abstractNum")
.First(a => (int)a.Attribute(w + "abstractNumId") == mappedAbsId);
var ilvls = mappedAbsElem
.Elements(w + "lvl")
.Select(l => (int)l.Attribute(w + "ilvl"))
.ToList();
foreach (var i in ilvls)
{
var lo = clonedNum.Elements(w + "lvlOverride")
.FirstOrDefault(x => (int?)x.Attribute(w + "ilvl") == i);
if (lo == null)
{
lo = new XElement(w + "lvlOverride", new XAttribute(w + "ilvl", i));
clonedNum.Add(lo);
}
if (lo.Element(w + "startOverride") == null)
{
lo.Add(new XElement(w + "startOverride", new XAttribute(w + "val", 1)));
}
}
targetNumbering.Root.Add(clonedNum);
}
// 5) Update paragraphs
var updatedParagraphs = new List();
foreach (var para in sourceDoc.MainDocumentPart.Document.Body.Elements())
{
var paraClone = XElement.Parse(para.OuterXml);
var pPr = paraClone.Element(w + "pPr");
if (pPr == null)
{
pPr = new XElement(w + "pPr");
paraClone.AddFirst(pPr);
}
var numPr = pPr.Element(w + "numPr");
if (numPr == null)
{
numPr = new XElement(w + "numPr");
pPr.Add(numPr);
}
var numIdElem = numPr.Element(w + "numId");
if (numIdElem != null)
{
var valAttr = numIdElem.Attribute(w + "val");
if (valAttr != null && int.TryParse(valAttr.Value, out int originalNumId))
{
if (srcNumToAbsSignature.TryGetValue(originalNumId, out string absSignature))
{
if (GlobalNumIdMap.TryGetValue((docGuid, originalNumId, absSignature), out int mappedNumId))
{
// copy ilvl from source paragraph
var srcIlvlElem = paraClone.Descendants(w + "ilvl").FirstOrDefault();
if (srcIlvlElem != null)
{
var ilvlVal = srcIlvlElem.Attribute(w + "val")?.Value ?? "0";
var numPrIlvl = numPr.Element(w + "ilvl");
if (numPrIlvl != null)
numPrIlvl.SetAttributeValue(w + "val", ilvlVal);
else
numPr.Add(new XElement(w + "ilvl", new XAttribute(w + "val", ilvlVal)));
}
// set mapped numId
numIdElem.SetAttributeValue(w + "val", mappedNumId);
}
}
}
}
updatedParagraphs.Add(paraClone);
}
// 6) Save updated numbering.xml
using (var ms = new MemoryStream())
{
ms.Write(targetBytes, 0, targetBytes.Length);
ms.Position = 0;
using (var wDoc = WordprocessingDocument.Open(ms, true))
{
var mainPart = wDoc.MainDocumentPart;
var numberingPart = mainPart.NumberingDefinitionsPart ??
mainPart.AddNewPart();
using (var partStream = numberingPart.GetStream(FileMode.Create, FileAccess.Write))
{
targetNumbering.Save(partStream);
}
mainPart.Document.Save();
}
ms.Position = 0;
targetWml = new WmlDocument(targetWml.FileName, ms.ToArray());
}
return new NumberingResult
{
UpdatedDoc = targetWml,
UpdatedParagraphs = updatedParagraphs
};
}
}
Подробнее здесь: https://stackoverflow.com/questions/787 ... ing-into-o
Как я могу вставить XML в документ Word без списков нумерации в одну последовательность? ⇐ C#
Место общения программистов C#
1757502468
Anonymous
Я пытаюсь объединить несколько документов Word (.docx), используя OpenXML в C#. Само слияние работает, но у меня есть постоянная проблема с пронумерованными и пуленами списками. Второе
имеет цифры → все списки в объединенном файле становятся числами. < /li>
Если в первом документе есть цифры, а второй имеет пули → Все списки в объединенном файле становятся пулями. /> < /ul>
Кажется, что в целевом документе < /strong> «strong>» [b] в последнее время. Документ. < /li>
Создание новых атрибутов NSID и имен в списке, чтобы избежать столкновений. < /li>
Образцы отслеживания с словарями для Numid и Abstractnumid. < /li>
Обеспечение начального оборудования. Магия происходит в numberHelper.mycodeHelper () [/b]. Я хотел бы избежать публикации всего этого кода и просто дать мой вывод XML для каждого источника и нумерацию. Xml целевого документа, и, возможно, кто -то сможет сказать мне, где я ошибаюсь, потому что, как я понимаю, XML не имеет никаких явных идентификационных выпусков. var targetDoc = targetWml
NumberHelper.ResetGlobalMaps();
foreach (var sourceDoc in sourceDocs)
{
var result = NumberHelper.MyCodeHelper(WordprocessingDocument sourceDoc, WmlDocument targetDoc);
targetDoc = result.UpdatedDoc;
updatedParagraphs = result.UpdatedParagraphs;
//I then have some code here that I am using to insert the result.UpdatedPargraphs into the targetDoc. This code is not having any issues. It is a numbering.xml issue, I am almost certain.
}
[b] source1 [/b] xml, который я вставляю и изображает его появление в документе.
This is atest
asdfads
fasdfasdfad
fasdfads
asdfasdf
asdfasdfsdf
asdfdsaf
adsfasdfasdf
asdfasdfasdf
asdfadsfasdfdsafasdf
[b] source2 [/b] xml, который я вставляю и изображает его появление в документе.
This iadfasdf adf
asdfasd
fasdfasdf
asdfasdfasd
fasdfasd
fadsafs
adsfasdfasd
asdfa
sdfasdfadsf
asdfsdf
< /code>
Результаты - как он появляется в окончательном документе. РЕДАКТИРОВАТЬ: Удал окончательный документ XML для публикации кода ниже:
edit:
ЗДЕСЬ. Я должен удалить вывод XML, который я получаю, чтобы опубликовать это. < /P>
public static class NumberingHelper
{
// Maps (docId, srcAbsId, signature) → mapped abstractNumId
private static readonly Dictionary GlobalAbstractNumIdMap
= new Dictionary();
// Maps (docId, srcNumId, signature) → mapped numId
private static readonly Dictionary GlobalNumIdMap
= new Dictionary();
// Maps srcNumId → absSignature (per document, temporary)
private static readonly Dictionary SrcNumToAbsSignature
= new Dictionary();
private static int maxAbsNumId = 0;
private static int maxNumId = 0;
public static void ResetGlobalMaps()
{
GlobalAbstractNumIdMap.Clear();
GlobalNumIdMap.Clear();
SrcNumToAbsSignature.Clear();
}
public static NumberingResult CopyNumberingAndParagraphs(
WordprocessingDocument sourceDoc,
WmlDocument targetWml)
{
XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
//XNamespace w = "";
byte[] targetBytes = targetWml.DocumentByteArray;
// 1) Load source numbering
XDocument sourceNumbering = null;
if (sourceDoc?.MainDocumentPart?.NumberingDefinitionsPart != null)
{
using (var reader = new StreamReader(sourceDoc.MainDocumentPart.NumberingDefinitionsPart.GetStream()))
{
sourceNumbering = XDocument.Load(reader);
}
}
if (sourceNumbering == null)
return new NumberingResult { UpdatedDoc = targetWml, UpdatedParagraphs = new List() };
// 2) Load target numbering (or create new)
XDocument targetNumbering;
using (var msLoad = new MemoryStream(targetBytes))
using (var wDocLoad = WordprocessingDocument.Open(msLoad, false))
{
var mainPart = wDocLoad.MainDocumentPart;
var numberingPart = mainPart.NumberingDefinitionsPart;
if (numberingPart != null)
{
using (var reader = new StreamReader(numberingPart.GetStream()))
targetNumbering = XDocument.Load(reader);
}
else
{
targetNumbering = new XDocument(
new XElement(w + "numbering",
new XAttribute(XNamespace.Xmlns + "w", w.NamespaceName)));
}
}
// 3) Determine max IDs in target numbering
int maxAbsNumId = targetNumbering.Descendants(w + "abstractNum")
.Select(a => (int?)a.Attribute(w + "abstractNumId"))
.DefaultIfEmpty(0)
.Max() ?? 0;
int maxNumId = targetNumbering.Descendants(w + "num")
.Select(n => (int?)n.Attribute(w + "numId"))
.DefaultIfEmpty(0)
.Max() ?? 0;
// Unique prefix for this source doc instance
string docGuid = (sourceDoc?.PackageProperties?.Identifier) ?? Guid.NewGuid().ToString("N");
var srcNumToAbsSignature = new Dictionary();
// 4) Copy elements from source
foreach (var srcNum in sourceNumbering.Descendants(w + "num"))
{
var numAttr = srcNum.Attribute(w + "numId");
if (numAttr == null || !int.TryParse(numAttr.Value, out int srcNumId))
continue;
var absElem = srcNum.Element(w + "abstractNumId");
if (absElem == null)
continue;
var absAttr = absElem.Attribute(w + "val");
if (absAttr == null || !int.TryParse(absAttr.Value, out int srcAbsId))
continue;
var srcAbs = sourceNumbering.Descendants(w + "abstractNum")
.FirstOrDefault(a =>
{
var aAttr = a.Attribute(w + "abstractNumId");
return aAttr != null &&
int.TryParse(aAttr.Value, out int v) &&
v == srcAbsId;
});
if (srcAbs == null)
continue;
// Build unique signature
string absSignature = string.Join("|",
new[] {
(string)srcAbs.Element(w + "multiLevelType")?.Attribute(w + "val") ?? "",
(string)srcAbs.Element(w + "nsid")?.Attribute(w + "val") ?? ""
}
.Concat(
srcAbs.Elements(w + "lvl").Select(l =>
$"{(int?)l.Attribute(w + "ilvl") ?? -1}-" +
$"{(string)l.Element(w + "numFmt")?.Attribute(w + "val") ?? ""}-" +
$"{(string)l.Element(w + "lvlText")?.Attribute(w + "val") ?? ""}-" +
$"{(string)l.Element(w + "lvlJc")?.Attribute(w + "val") ?? ""}-" +
$"{(string)l.Element(w + "isLgl")?.Attribute(w + "val") ?? ""}"
)
)
);
var absKey = ((docGuid, srcAbsId), absSignature + "|" + docGuid);
if (!GlobalAbstractNumIdMap.TryGetValue(absKey, out int mappedAbsId))
{
var clonedAbs = new XElement(srcAbs);
mappedAbsId = ++maxAbsNumId;
clonedAbs.SetAttributeValue(w + "abstractNumId", mappedAbsId);
// generate fresh nsid
var newNsid = Guid.NewGuid().ToString("N").Substring(0, 8).ToUpperInvariant();
var nsidElem = clonedAbs.Element(w + "nsid");
if (nsidElem != null) nsidElem.SetAttributeValue(w + "val", newNsid);
else clonedAbs.Add(new XElement(w + "nsid", new XAttribute(w + "val", newNsid)));
// give it its own name
var nameElem = clonedAbs.Element(w + "name");
if (nameElem != null) nameElem.SetAttributeValue(w + "val", $"List_{newNsid}");
else clonedAbs.Add(new XElement(w + "name", new XAttribute(w + "val", $"List_{newNsid}")));
// ensure multiLevelType is preserved
var multiElem = srcAbs.Element(w + "multiLevelType");
if (multiElem != null)
clonedAbs.Add(new XElement(w + "multiLevelType",
new XAttribute(w + "val", multiElem.Attribute(w + "val")?.Value)));
targetNumbering.Root.Add(clonedAbs);
GlobalAbstractNumIdMap[absKey] = mappedAbsId;
}
int newNumForThis = ++maxNumId;
GlobalNumIdMap[(docGuid, srcNumId, absSignature)] = newNumForThis;
srcNumToAbsSignature[srcNumId] = absSignature;
var clonedNum = new XElement(srcNum);
clonedNum.SetAttributeValue(w + "numId", newNumForThis);
var absRefElem = clonedNum.Element(w + "abstractNumId");
if (absRefElem != null)
absRefElem.SetAttributeValue(w + "val", mappedAbsId);
else
clonedNum.Add(new XElement(w + "abstractNumId",
new XAttribute(w + "val", mappedAbsId)));
// Add lvlOverride resets
var mappedAbsElem = targetNumbering
.Descendants(w + "abstractNum")
.First(a => (int)a.Attribute(w + "abstractNumId") == mappedAbsId);
var ilvls = mappedAbsElem
.Elements(w + "lvl")
.Select(l => (int)l.Attribute(w + "ilvl"))
.ToList();
foreach (var i in ilvls)
{
var lo = clonedNum.Elements(w + "lvlOverride")
.FirstOrDefault(x => (int?)x.Attribute(w + "ilvl") == i);
if (lo == null)
{
lo = new XElement(w + "lvlOverride", new XAttribute(w + "ilvl", i));
clonedNum.Add(lo);
}
if (lo.Element(w + "startOverride") == null)
{
lo.Add(new XElement(w + "startOverride", new XAttribute(w + "val", 1)));
}
}
targetNumbering.Root.Add(clonedNum);
}
// 5) Update paragraphs
var updatedParagraphs = new List();
foreach (var para in sourceDoc.MainDocumentPart.Document.Body.Elements())
{
var paraClone = XElement.Parse(para.OuterXml);
var pPr = paraClone.Element(w + "pPr");
if (pPr == null)
{
pPr = new XElement(w + "pPr");
paraClone.AddFirst(pPr);
}
var numPr = pPr.Element(w + "numPr");
if (numPr == null)
{
numPr = new XElement(w + "numPr");
pPr.Add(numPr);
}
var numIdElem = numPr.Element(w + "numId");
if (numIdElem != null)
{
var valAttr = numIdElem.Attribute(w + "val");
if (valAttr != null && int.TryParse(valAttr.Value, out int originalNumId))
{
if (srcNumToAbsSignature.TryGetValue(originalNumId, out string absSignature))
{
if (GlobalNumIdMap.TryGetValue((docGuid, originalNumId, absSignature), out int mappedNumId))
{
// copy ilvl from source paragraph
var srcIlvlElem = paraClone.Descendants(w + "ilvl").FirstOrDefault();
if (srcIlvlElem != null)
{
var ilvlVal = srcIlvlElem.Attribute(w + "val")?.Value ?? "0";
var numPrIlvl = numPr.Element(w + "ilvl");
if (numPrIlvl != null)
numPrIlvl.SetAttributeValue(w + "val", ilvlVal);
else
numPr.Add(new XElement(w + "ilvl", new XAttribute(w + "val", ilvlVal)));
}
// set mapped numId
numIdElem.SetAttributeValue(w + "val", mappedNumId);
}
}
}
}
updatedParagraphs.Add(paraClone);
}
// 6) Save updated numbering.xml
using (var ms = new MemoryStream())
{
ms.Write(targetBytes, 0, targetBytes.Length);
ms.Position = 0;
using (var wDoc = WordprocessingDocument.Open(ms, true))
{
var mainPart = wDoc.MainDocumentPart;
var numberingPart = mainPart.NumberingDefinitionsPart ??
mainPart.AddNewPart();
using (var partStream = numberingPart.GetStream(FileMode.Create, FileAccess.Write))
{
targetNumbering.Save(partStream);
}
mainPart.Document.Save();
}
ms.Position = 0;
targetWml = new WmlDocument(targetWml.FileName, ms.ToArray());
}
return new NumberingResult
{
UpdatedDoc = targetWml,
UpdatedParagraphs = updatedParagraphs
};
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/78755294/how-can-i-insert-xml-into-a-word-document-without-numbering-lists-merging-into-o[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия